package bots;

import model.*;

import java.util.*;

/**
 * @author Alex Vikharev alex.vikharev@gmail.com
 *         created 25.01.12
 */
public abstract class AbstractBot implements Player {

    protected final Random random = new Random();
    protected final String name;
    protected final GameType gameType;

    public AbstractBot(String name, GameType gameType) {
        this.name = name;
        this.gameType = gameType;
    }

    public List<Figure> freeFigures(Field field, Figure figure) {
        EnumSet<Figure> usedFigures;
        if (field.getUsedFigures().isEmpty()) {
            usedFigures = EnumSet.noneOf(Figure.class);
        } else {
            usedFigures = EnumSet.copyOf(field.getUsedFigures());
        }
        if (figure != null) {
            usedFigures.add(figure);
        }
        return new ArrayList<>(EnumSet.complementOf(usedFigures));
    }

    public Position setRandomFigure(Field field, Figure figure) {
        Set<Figure> usedFigures;
        if (field.getUsedFigures().isEmpty()) {
            usedFigures = EnumSet.noneOf(Figure.class);
        } else {
            usedFigures = EnumSet.copyOf(field.getUsedFigures());
        }
        usedFigures.add(figure);
        List<Figure> freeFigures = new ArrayList<>(EnumSet.complementOf(EnumSet.copyOf(usedFigures)));
        int skip = usedFigures.size() == 16 ? 0 : random.nextInt(16 - usedFigures.size());

        int x = -1;
        int y = -1;

        outer:
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (field.get(j, i) == null) {
                    if (skip <= 0) {
                        x = j;
                        y = i;
                        break outer;
                    } else {
                        skip--;
                    }
                }
            }
        }


        Field newField = field.addFigure(x, y, figure);
        Collections.shuffle(freeFigures, random);
        Figure newFigure = freeFigures.size() == 0 ? null : freeFigures.get(0);

        return new Position(newField, newFigure);

    }

    @Override
    public String toString() {
        return name;
    }

    protected Position getWinMove(Field field, Figure figure) {
        List<Figure> freeFigures = freeFigures(field, figure);
        Figure newFigure;
        if (freeFigures.isEmpty()) {
            newFigure = null;
        } else {
            newFigure = freeFigures.get(0);
        }

        for (int y = 0; y < 4; y++) {
            for (int x = 0; x < 4; x++) {
                if (field.get(x, y) == null) {
                    Field newField = field.addFigure(x, y, figure);
                    if (newField.isGameOver(gameType)) {
                        return new Position(newField, newFigure);
                    }
                }
            }
        }
        return null;
    }

    protected List<Position> getPossibleMoves(Field field, Figure figure) {
        List<Position> possibleMoves = new ArrayList<>();
        List<Figure> freeFigures = freeFigures(field, figure);
        for (int x = 0; x < 4; x++) {
            for (int y = 0; y < 4; y++) {
                if (field.get(x, y) == null) {
                    if (freeFigures.isEmpty()) {
                        possibleMoves.add(new Position(field.addFigure(x, y, figure), null));
                    } else {
                        for (Figure freeFigure : freeFigures) {
                            possibleMoves.add(new Position(field.addFigure(x, y, figure), freeFigure));
                        }
                    }
                }
            }
        }
        return possibleMoves;
    }
}
